package com.ruoyi.common.utils;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author taoism
 * @date 2019/9/2
 */
public class RSAUtils
{
    
    /**
     * 缺省的1024位密钥对,可处理245个字节(81个汉字)的数据
     */
    public static String PRIVATE_KEY =
        "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJTwGVzXREBzJNMiNGHkDdnjnRBXhQA6HJgz9Hf0FfacvUAbu/nTmwUxvz9lbpJwvpKcL7Y425fYm+FpepmY1ICG4tgudVPI6Mxd3zLnpOocHxuhgpuXJ4vSgjMr84diPpySMwoR5StHkT1NtovLTMPf3lpMDgygr8BsVA2PiFPdAgMBAAECgYAApKTHZNqTmKuxCbXGMnDo3vW/q1EUtiuHcLn+hpxNq1GZ5ETEiGhj9loIEQ0QLtJz2Z7PH6G7HyFVMNpprWJFhh/dk0T85FkSp9hyzcS6WNfLRsMgvHiLgcDueJxIr9hiDs1QD+9u1GlLtRnQfJXSHMgmiiUhk82dHscIDw79AQJBAMRMqJ7tUuQJIVgrsuBS2NdqJjXHd/icuoqznUXnItSMgZ5f+Dk/hUoli9GKmkCaEP/GDK2YNTd8EQTMTl4F2EECQQDCO/9+vTp7+P5Rl8ZkA0Now1L+0GYEgcqtoScMQ03SYa8jbshZjlduYaKnHr9teRQGwSvhsrNJXkU2i4NopbSdAkEAriTDwpoP2zUuW6YIvnFA5XnKBBO9HtULuFi3wXfXsnAj3XiOIVt0x96fN3mado03X3E3dhl9vIdYIcWOEGNnAQJAP/CMTOZyCDmRTr7N2kKQwD38ZlGoI7euRrYUKp9FUQpDI0Dmx0RqV7XgW29tyNXg19BjZ6ryBib4VdpbaemSqQJALywvANk2tyjsoR6BCK5XJBFzdu4vX5Ntru4RNijGHHViDqyNTlPPbY0kt9+qBPNvAMLO0BuNeFFBxGh7pgtk5w==";
    
    public static String PUBLIC_KEY =
        "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCU8Blc10RAcyTTIjRh5A3Z450QV4UAOhyYM/R39BX2nL1AG7v505sFMb8/ZW6ScL6SnC+2ONuX2JvhaXqZmNSAhuLYLnVTyOjMXd8y56TqHB8boYKblyeL0oIzK/OHYj6ckjMKEeUrR5E9TbaLy0zD395aTA4MoK/AbFQNj4hT3QIDAQAB";
    
    /**
     * 字符集
     */
    public static String CHARSET = "utf-8";
    
    /**
     * 签名算法
     */
    public static final String SIGNATURE_INSTANCE = "SHA1WithRSA";
    
    /**
     * 非对称加密密钥算法
     */
    public static final String KEY_ALGORITHM_RSA = "RSA";
    
    /**
     * RSA密钥长度 默认1024位， 密钥长度必须是64的倍数， 范围在512至65536位之间。
     */
    private static final int KEY_SIZE = 1024;
    
    /**
     * 生成密钥对
     *
     * @param keysize
     * @return
     * @throws Exception
     */
    public static KeyPair getKeyPair(int keysize)
        throws Exception
    {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM_RSA);
        keyPairGenerator.initialize(keysize);
        return keyPairGenerator.generateKeyPair();
    }
    
    /**
     * 生成密钥对
     *
     * @return
     * @throws Exception
     */
    public static KeyPair getKeyPair()
        throws Exception
    {
        return getKeyPair(KEY_SIZE);
    }
    
    /**
     * 生成密钥对
     *
     * @param seed
     * @return
     * @throws Exception
     */
    public static KeyPair getKeyPair(byte[] seed)
        throws Exception
    {
        
        // 实例化密钥对生成器
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM_RSA);
        
        // 初始化密钥对生成器
        keyPairGen.initialize(KEY_SIZE, new SecureRandom(seed));
        
        // 生成密钥对
        return keyPairGen.generateKeyPair();
    }
    
    /**
     * 生成密钥对
     *
     * @param seed
     * @return
     * @throws Exception
     */
    public static KeyPair getKeyPair(String seed)
        throws Exception
    {
        
        return getKeyPair(seed.getBytes(CHARSET));
    }
    
    /**
     * 公钥字符串转PublicKey实例
     *
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(String publicKey)
        throws Exception
    {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey.getBytes(CHARSET));
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_RSA);
        return keyFactory.generatePublic(keySpec);
    }
    
    /**
     * 私钥字符串转PrivateKey实例
     *
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String privateKey)
        throws Exception
    {
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey.getBytes(CHARSET));
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_RSA);
        return keyFactory.generatePrivate(keySpec);
    }
    
    /**
     * 公钥加密
     *
     * @param content
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] content, PublicKey publicKey)
        throws Exception
    {
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_RSA);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(content);
    }
    
    public static byte[] encryptByPublicKey(byte[] content)
        throws Exception
    {
        return encryptByPublicKey(content, getPublicKey(PUBLIC_KEY));
    }
    
    public static String encryptByPublicKey(String content, String publicKey)
        throws Exception
    {
        
        byte[] encode =
            Base64.getEncoder().encode(encryptByPublicKey(content.getBytes(CHARSET), getPublicKey(publicKey)));
        
        return new String(encode, CHARSET);
        
    }
    
    public static String encryptByPublicKey(String content)
        throws Exception
    {
        return new String(Base64.getEncoder().encode(encryptByPublicKey(content.getBytes(CHARSET))), CHARSET);
    }
    
    /**
     * 私钥解密
     *
     * @param content
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] content, PrivateKey privateKey)
        throws Exception
    {
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_RSA);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(content);
    }
    
    public static byte[] decryptByPrivateKey(byte[] content)
        throws Exception
    {
        return decryptByPrivateKey(content, getPrivateKey(PRIVATE_KEY));
    }
    
    public static String decryptByPrivateKey(String content, String privateKey)
        throws Exception
    {
        return new String(decryptByPrivateKey(Base64.getDecoder().decode(content), getPrivateKey(privateKey)), CHARSET);
        
    }
    
    public static String decryptByPrivateKey(String content)
        throws Exception
    {
        return new String(decryptByPrivateKey(Base64.getDecoder().decode(content)), CHARSET);
    }
    
    /**
     * 私钥加密
     *
     * @param content
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] content, PrivateKey privateKey)
        throws Exception
    {
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_RSA);
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(content);
    }
    
    public static byte[] encryptByPrivateKey(byte[] content)
        throws Exception
    {
        return encryptByPrivateKey(content, getPrivateKey(PRIVATE_KEY));
    }
    
    public static String encryptByPrivateKey(String content, String privateKey)
        throws Exception
    {
        return Base64.getEncoder()
            .encodeToString(encryptByPrivateKey(content.getBytes(CHARSET), getPrivateKey(privateKey)));
    }
    
    public static String encryptByPrivateKey(String content)
        throws Exception
    {
        return Base64.getEncoder().encodeToString(encryptByPrivateKey(content.getBytes(CHARSET)));
    }
    
    /**
     * 公钥解密
     *
     * @param content
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] content, PublicKey publicKey)
        throws Exception
    {
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_RSA);
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(content);
    }
    
    public static byte[] decryptByPublicKey(byte[] content)
        throws Exception
    {
        return decryptByPublicKey(content, getPublicKey(PUBLIC_KEY));
    }
    
    public static String decryptByPublicKey(String content, String publicKey)
        throws Exception
    {
        return new String(decryptByPublicKey(Base64.getDecoder().decode(content), getPublicKey(publicKey)), CHARSET);
        
    }
    
    public static String decryptByPublicKey(String content)
        throws Exception
    {
        return new String(decryptByPublicKey(Base64.getDecoder().decode(content)), CHARSET);
    }
    
    /**
     * 签名
     *
     * @param content
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] sign(byte[] content, PrivateKey privateKey)
        throws Exception
    {
        Signature signature = Signature.getInstance(SIGNATURE_INSTANCE);
        signature.initSign(privateKey);
        signature.update(content);
        return signature.sign();
    }
    
    public static byte[] sign(byte[] content)
        throws Exception
    {
        return sign(content, getPrivateKey(PRIVATE_KEY));
    }
    
    public static String sign(String content, String privateKey)
        throws Exception
    {
        return new String(Base64.getEncoder().encode(sign(content.getBytes(CHARSET), getPrivateKey(privateKey))),
            CHARSET);
    }
    
    public static String sign(String content)
        throws Exception
    {
        return new String(Base64.getEncoder().encode(sign(content.getBytes(CHARSET))), CHARSET);
    }
    
    /**
     * 验签
     *
     * @param content
     * @param sign
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static boolean verify(byte[] content, byte[] sign, PublicKey publicKey)
        throws Exception
    {
        Signature signature = Signature.getInstance(SIGNATURE_INSTANCE);
        signature.initVerify(publicKey);
        signature.update(content);
        return signature.verify(sign);
    }
    
    public static boolean verify(byte[] content, byte[] sign)
        throws Exception
    {
        return verify(content, sign, getPublicKey(PUBLIC_KEY));
    }
    
    public static boolean verify(String content, String sign, String publicKey)
        throws Exception
    {
        return verify(content.getBytes(CHARSET), Base64.getDecoder().decode(sign), getPublicKey(publicKey));
    }
    
    public static boolean verify(String content, String sign)
        throws Exception
    {
        return verify(content.getBytes(CHARSET), Base64.getDecoder().decode(sign), getPublicKey(PUBLIC_KEY));
    }
}
